package cn.ichensw.otherworldlystationbackend.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.ichensw.otherworldlystationbackend.common.DoubanPageRequest;
import cn.ichensw.otherworldlystationbackend.common.ErrorCode;
import cn.ichensw.otherworldlystationbackend.constant.DoubanConstant;
import cn.ichensw.otherworldlystationbackend.exception.BusinessException;
import cn.ichensw.otherworldlystationbackend.model.dto.douban.DoubanSearchMovieRequest;
import cn.ichensw.otherworldlystationbackend.model.entity.FilmTelevision;
import cn.ichensw.otherworldlystationbackend.model.entity.FilmTelevisionUser;
import cn.ichensw.otherworldlystationbackend.model.entity.User;
import cn.ichensw.otherworldlystationbackend.model.vo.PersonIntroductVO;
import cn.ichensw.otherworldlystationbackend.model.vo.bangumi.ImageVO;
import cn.ichensw.otherworldlystationbackend.model.vo.douban.DoubanMovieUsBoxVO;
import cn.ichensw.otherworldlystationbackend.model.vo.douban.DoubanSearchMovieVO;
import cn.ichensw.otherworldlystationbackend.service.DoubanService;
import cn.ichensw.otherworldlystationbackend.service.FilmTelevisionService;
import cn.ichensw.otherworldlystationbackend.service.FilmTelevisionUserService;
import cn.ichensw.otherworldlystationbackend.service.UserService;
import cn.ichensw.otherworldlystationbackend.utils.RedisUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.util.DateUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
 * 豆瓣接口Service实现类
 *
 * @author csw
 */
@Service
@Slf4j
public class DoubanServiceImpl implements DoubanService {

    @Resource
    private UserService userService;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private FilmTelevisionService filmTelevisionService;
    @Resource
    private FilmTelevisionUserService filmTelevisionUserService;

    @Override
    public Page<DoubanSearchMovieVO> searchMovie(DoubanSearchMovieRequest request, HttpServletRequest httpServletRequest) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
        }

        // 构建请求参数
        Map<String, Object> params = new HashMap<>();
        if (!request.getSearchKeys().isEmpty()) {
            params.put("q", request.getSearchKeys());
        } else if (!request.getTag().isEmpty()) {
            params.put("tag", request.getTag());
        }
        params.put("start", request.getStart());
        params.put("count", request.getCount());
        params.put("apikey", DoubanConstant.API_KEY);

        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.SEARCH_MOVIE_HOST)
                .form(params)
                .execute();
        Page<DoubanSearchMovieVO> doubanSearchMovieVOPage = mappingResult(response, httpServletRequest);
        doubanSearchMovieVOPage.setCurrent(request.getStart());
        return doubanSearchMovieVOPage;
    }

    /**
     * 封装响应结果
     *
     * @param response           响应
     * @param httpServletRequest
     */
    private Page<DoubanSearchMovieVO> mappingResult(HttpResponse response, HttpServletRequest httpServletRequest) {
        if (response.getStatus() != HttpStatus.OK.value() || response.body() == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到相关影视信息");
        }
        List<DoubanSearchMovieVO> result = new ArrayList<>();
        Page<DoubanSearchMovieVO> page = new Page<>();

        User loginUser = userService.getLoginUser(httpServletRequest);

        JSONObject entries = JSONUtil.parseObj(response.body());
        // 电影列表
        JSONArray subjects = entries.getJSONArray("subjects");
        // 遍历单个电影信息,封装成VO
        subjects.forEach(subject -> {
            JSONObject object = (JSONObject) subject;
            DoubanSearchMovieVO searchMovieVO = new DoubanSearchMovieVO();
            long id = Long.parseLong(object.getStr("id"));

            searchMovieVO.setId(id);
            searchMovieVO.setTitle(object.getStr("title"));
            searchMovieVO.setYear(object.getStr("year"));
            searchMovieVO.setSubType(object.getStr("subtype"));
            searchMovieVO.setAverage(Optional.ofNullable(object.getJSONObject("rating").getBigDecimal("average"))
                    .map(Object::toString)
                    .map(BigDecimal::new)
                    .orElse(BigDecimal.ZERO));

            Integer value = (Integer) redisUtils.get(String.valueOf(loginUser.getId() + searchMovieVO.getId()));
            if (value != null) {
                searchMovieVO.setWatchStatus(value);
            }
            searchMovieVO.setImages(JSON.parseObject(object.getStr("images"), ImageVO.class));
            result.add(searchMovieVO);
        });
        page.setRecords(result);
        page.setSize(entries.getInt("count"));
        page.setTotal(entries.getInt("total"));
        return page;
    }

    @Override
    public Page<DoubanSearchMovieVO> movieTop250(DoubanPageRequest request, HttpServletRequest httpServletRequest) {
        // 构建请求参数
        Map<String, Object> params = buildDoubanRequestParams(request);

        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_TOP_250)
                .form(params)
                .execute();
        Page<DoubanSearchMovieVO> doubanSearchMovieVOPage = mappingResult(response, httpServletRequest);
        doubanSearchMovieVOPage.setCurrent(request.getStart());
        return doubanSearchMovieVOPage;
    }

    @Override
    public DoubanMovieUsBoxVO movieUsBox(DoubanPageRequest request, HttpServletRequest httpServletRequest) {
        // 构建请求参数
        Map<String, Object> params = buildDoubanRequestParams(request);
        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_US_BOX)
                .form(params)
                .execute();
        return movieUsBoxMappingResult(response, httpServletRequest);
    }

    private DoubanMovieUsBoxVO movieUsBoxMappingResult(HttpResponse response, HttpServletRequest httpServletRequest) {
        DoubanMovieUsBoxVO movieUsBoxResult = new DoubanMovieUsBoxVO();
        if (response.getStatus() != HttpStatus.OK.value() || response.body() == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到相关影视信息");
        }
        List<DoubanSearchMovieVO> result = new ArrayList<>();

        User loginUser = userService.getLoginUser(httpServletRequest);

        JSONObject entries = JSONUtil.parseObj(response.body());
        // 电影列表
        JSONArray subjects = entries.getJSONArray("subjects");
        // 遍历单个电影信息,封装成VO
        subjects.forEach(subject -> {
            JSONObject object = (JSONObject) subject;
            JSONObject subItem = (JSONObject) object.get("subject");
            DoubanSearchMovieVO searchMovieVO = new DoubanSearchMovieVO();
            long id = Long.parseLong(subItem.getStr("id"));
            searchMovieVO.setId(id);
            searchMovieVO.setTitle(subItem.getStr("title"));
            searchMovieVO.setYear(subItem.getStr("year"));
            searchMovieVO.setSubType(subItem.getStr("subtype"));
            searchMovieVO.setAverage(Optional.ofNullable(subItem.getJSONObject("rating").getBigDecimal("average"))
                    .map(Object::toString)
                    .map(BigDecimal::new)
                    .orElse(BigDecimal.ZERO));

            Integer value = (Integer) redisUtils.get(String.valueOf(loginUser.getId() + searchMovieVO.getId()));
            if (value != null) {
                searchMovieVO.setWatchStatus(value);
            }
            searchMovieVO.setImages(JSON.parseObject(subItem.getStr("images"), ImageVO.class));
            result.add(searchMovieVO);
        });
        movieUsBoxResult.setSearchMovies(result);
        movieUsBoxResult.setDate(entries.getStr("date"));
        return movieUsBoxResult;
    }
    @Override
    public Page<DoubanSearchMovieVO> movieWeekly(DoubanPageRequest request, HttpServletRequest httpServletRequest) {
        // 构建请求参数
        Map<String, Object> params = buildDoubanRequestParams(request);
        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_WEEKLY)
                .form(params)
                .execute();
        Page<DoubanSearchMovieVO> doubanSearchMovieVOPage = mappingResult(response, httpServletRequest);
        doubanSearchMovieVOPage.setCurrent(request.getStart());
        return doubanSearchMovieVOPage;
    }

    @Override
    public Page<DoubanSearchMovieVO> movieNew(DoubanPageRequest request, HttpServletRequest httpServletRequest) {
        // 构建请求参数
        Map<String, Object> params = buildDoubanRequestParams(request);
        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_NEW)
                .form(params)
                .execute();
        JSONObject entries = JSONUtil.parseObj(response.body());
        Page<DoubanSearchMovieVO> doubanSearchMovieVOPage = mappingResult(response, httpServletRequest);
        doubanSearchMovieVOPage.setCurrent(request.getStart());
        return doubanSearchMovieVOPage;
    }

    @Override
    public Page<DoubanSearchMovieVO> movieInTheaters(DoubanPageRequest request, HttpServletRequest httpServletRequest) {
        // 构建请求参数
        Map<String, Object> params = buildDoubanRequestParams(request);
        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_IN_THEATERS)
                .form(params)
                .execute();
        Page<DoubanSearchMovieVO> doubanSearchMovieVOPage = mappingResult(response, httpServletRequest);
        doubanSearchMovieVOPage.setCurrent(request.getStart());
        return doubanSearchMovieVOPage;
    }

    @Override
    public Page<DoubanSearchMovieVO> movieComingSoon(DoubanPageRequest request, HttpServletRequest httpServletRequest) {
        // 构建请求参数
        Map<String, Object> params = buildDoubanRequestParams(request);
        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_COMING_SOON)
                .form(params)
                .execute();
        Page<DoubanSearchMovieVO> doubanSearchMovieVOPage = mappingResult(response, httpServletRequest);
        doubanSearchMovieVOPage.setCurrent(request.getStart());
        return doubanSearchMovieVOPage;
    }

    private Map<String, Object> buildDoubanRequestParams(DoubanPageRequest request) {
        Map<String, Object> params = new HashMap<>(16);
        params.put("start", Optional.of(request.getStart() * request.getCount()).orElse(0));
        params.put("count", Optional.ofNullable(request.getCount()).orElse(20));
        params.put("apikey", DoubanConstant.API_KEY);
        return params;
    }

    @Override
    public DoubanSearchMovieVO movieSubjectDetail(Long id, HttpServletRequest httpServletRequest) {
        if (id == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
        }
        Long dbId = id + DoubanConstant.doubanIdPrefix;
        DoubanSearchMovieVO doubanSearchMovieVO = new DoubanSearchMovieVO();
        User loginUser = userService.getLoginUser(httpServletRequest);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户未登录");
        }
        Long userId = loginUser.getId();

        // 查询本地数据库中存在该影片
        FilmTelevision filmTelevision = filmTelevisionService.getById(dbId);
        if (filmTelevision != null) {
            doubanSearchMovieVO.setId(filmTelevision.getId());
            doubanSearchMovieVO.setTitle(filmTelevision.getName());
            doubanSearchMovieVO.setImages(JSON.parseObject(filmTelevision.getImages(), ImageVO.class));
            doubanSearchMovieVO.setSubType(filmTelevision.getType());
            doubanSearchMovieVO.setGenres(JSON.parseArray(filmTelevision.getTags(), String.class));
            doubanSearchMovieVO.setYear(DateUtils.format(filmTelevision.getReleaseDate(), "yyyy"));
            doubanSearchMovieVO.setAverage(filmTelevision.getScore());
            doubanSearchMovieVO.setSummary(filmTelevision.getDescription());

            // 查询用户是否收藏了该影片
            FilmTelevisionUser relationEntity = filmTelevisionUserService.lambdaQuery()
                    .eq(FilmTelevisionUser::getFilmId, dbId)
                    .eq(FilmTelevisionUser::getUserId, userId)
                    .one();
            if (relationEntity != null) {
                doubanSearchMovieVO.setWatchStatus(relationEntity.getWatchStatus());
            }
            return doubanSearchMovieVO;
        }
        // 请求豆瓣接口，获取响应
        HttpResponse response = HttpRequest.post(DoubanConstant.MOVIE_SUBJECT_DETAIL + id)
                .form("apikey", DoubanConstant.API_KEY)
                .execute();


        if (response.getStatus() != HttpStatus.OK.value() || response.body() == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到相关影视信息");
        }

        JSONObject jsonObject = JSONUtil.parseObj(response.body());
        doubanSearchMovieVO.setId(jsonObject.getLong("id") + DoubanConstant.doubanIdPrefix);
        doubanSearchMovieVO.setTitle(jsonObject.getStr("title"));
        doubanSearchMovieVO.setGenres(jsonObject.getJSONArray("genres").toList(String.class));
        List<PersonIntroductVO> directors = jsonObject.getJSONArray("directors").toList(PersonIntroductVO.class);
        doubanSearchMovieVO.setDirectors(directors);
        List<PersonIntroductVO> casts = jsonObject.getJSONArray("casts").toList(PersonIntroductVO.class);
        doubanSearchMovieVO.setCasts(casts);
        doubanSearchMovieVO.setCollectCount(jsonObject.getInt("collect_count"));
        doubanSearchMovieVO.setWishCount(jsonObject.getInt("wish_count"));
        doubanSearchMovieVO.setRatingsCount(jsonObject.getInt("ratings_count"));
        doubanSearchMovieVO.setSummary(jsonObject.getStr("summary"));
        doubanSearchMovieVO.setAka(jsonObject.getJSONArray("aka").toList(String.class));
        doubanSearchMovieVO.setAlt(jsonObject.getStr("alt"));
        doubanSearchMovieVO.setMobileUrl(jsonObject.getStr("mobile_url"));
        doubanSearchMovieVO.setImages(JSON.parseObject(jsonObject.getStr("images"), ImageVO.class));
        String subtype = Optional.ofNullable(jsonObject.getStr("subtype")).orElse("");
        if (subtype.equals("movie")) {
            doubanSearchMovieVO.setSubType("电影");
        } else {
            doubanSearchMovieVO.setSubType("剧集");
        }
        doubanSearchMovieVO.setYear(jsonObject.getStr("year"));
        doubanSearchMovieVO.setAverage(Optional.ofNullable(jsonObject.getJSONObject("rating").getBigDecimal("average"))
                .map(Object::toString)
                .map(BigDecimal::new)
                .orElse(BigDecimal.ZERO));

        Integer value = (Integer) redisUtils.get(String.valueOf(userId + doubanSearchMovieVO.getId()));
        if (value != null) {
            doubanSearchMovieVO.setWatchStatus(value);
        }

        return doubanSearchMovieVO;
    }
}
